from typing import Union

from fastapi import APIRouter, Depends, HTTPException, status, Form, Request
from fastapi.security import OAuth2PasswordRequestForm
from sqlalchemy.orm import Session
from jose import JWTError, jwt

import crud, schemas, models
from database import get_db, get_casbin_e
from schemas import Token, TokenData
from utils import verify_password, APP_TOKEN_CONFIG, oauth2_scheme, get_username_by_token, get_password_hash, verify_enforce, update_array

from api.api_v1.tools.json_resonse import sucessResonse, errorResponse
from objtyping import to_primitive

casbin_router = router = APIRouter(
    prefix="/v1",
    tags=["casbin_v1"],
    responses={404: {"description": "Not found"}},  # 请求异常返回数据
)

no_permission = HTTPException(
    status_code=status.HTTP_403_FORBIDDEN,
    detail="您没有该权限！",
    headers={"WWW-Authenticate": "Bearer"},
)

def return_rule(obj, act):
    """
    返回一个验证权限的规则，包括obj、act。
    :param obj:
    :param act:
    :return:
    """
    return schemas.Casbin_rule(obj=obj, act=act)

######################################
# CasbinObject相关的api接口
######################################

@router.get('/co/get_cos')
async def get_cos(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db), skip: int = 0, limit: int = 10, keyword: str = ''):
    data = schemas.CasbinObjects(list=crud.get_casbin_objects_with_params(db, (skip - 1) * limit, limit, keyword), count=crud.get_casbin_objects_count_by_keyword(db, keyword))
    return sucessResonse(data=to_primitive(data))

@router.post('/co/create_co')
async def create_casbin_object(co: schemas.createCasbinObject, token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
    """
    创建资源
    :param co:
    :param token:
    :param db:
    :return:
    """
    if verify_enforce(token, return_rule('CasbinObject', 'create')):
        new_co = models.CasbinObject()
        new_co.name = co.name
        new_co.object_key = co.object_key
        new_co.description = co.description
        new_co.user_id = co.user_id
        data = crud.create_casbin_object(db, new_co)
        if data:
            return sucessResonse(data = data)
        else :
            return errorResponse(data = data)
    else:
        raise no_permission

@router.get('/co/get_co')
async def get_casbin_object(co_id: int, token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
    return crud.get_casbin_object_by_id(db, co_id)

@router.post('/co/update_co')
async def update_casbin_object_by_id(co: schemas.EditCasbinObject, token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
    if verify_enforce(token, return_rule('CasbinObject', 'update')):
        data = crud.update_casbin_object(db, co.id, co.name, co.object_key, co.description)
        if data:
            return sucessResonse(data = data)
        else :
            return errorResponse(data = data)
    else:
        raise no_permission

@router.get('/co/delete_co')
async def delete_casbin_object_by_id(id: int, token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
    if verify_enforce(token, return_rule('CasbinObject', 'read')):
        data = crud.delete_casbin_object_by_id(db, id)
        if data:
            return sucessResonse(data = data)
        else :
            return errorResponse(data = data)
    else:
        raise no_permission

######################################
# CasbinAction相关的api接口
######################################

@router.get('/ca/get_cas')
async def get_cas(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db), skip: int = 0, limit: int = 10, keyword: str = ''):
    data = schemas.CasbinActions(list=crud.get_casbin_actions_with_params(db, (skip - 1) * limit, limit, keyword), count=crud.get_casbin_actions_count_by_keyword(db, keyword))
    return sucessResonse(data=to_primitive(data))

@router.post('/ca/create_ca')
async def create_ca(ca: schemas.createCasbinAction, token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
    if verify_enforce(token, return_rule('CasbinAction', 'create')):
        new_ca = models.CasbinAction()
        new_ca.name = ca.name
        new_ca.action_key = ca.action_key
        new_ca.description = ca.description
        new_ca.user_id = ca.user_id
        data = crud.create_casbin_action(db, new_ca)
        if data:
            return sucessResonse(data = data)
        else :
            return errorResponse(data = data)
    else:
        raise no_permission

@router.get('/ca/get_ca')
async def get_ca(ca_id: int, token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
    return crud.get_casbin_action_by_id(db, ca_id)

@router.post('/ca/update_ca')
async def update_ca(ca: schemas.EditCasbinAction, token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
    if verify_enforce(token, return_rule('CasbinAction', 'update')):
        data = to_primitive(crud.update_casbin_action_by_id(db, ca.id, ca.name, ca.action_key, ca.description))
        if data:
            return sucessResonse(data = data)
        else :
            return errorResponse(data = data)
    else:
        raise no_permission

@router.get('/ca/delete_ca')
async def delete_ca(id: int, token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
    if verify_enforce(token, return_rule('CasbinAction', 'delete')):
        data =  to_primitive(crud.delete_casbin_action_by_id(db, id))
        if data:
            return sucessResonse(data = data)
        else :
            return errorResponse(data = data)
    else:
        raise no_permission

######################################
# Casbin 权限验证的api接口
######################################

@router.get('/get_menu')
async def get_menu_permissions(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
    rules = [
        ['User', 'show'],
        ['Role', 'show'],
        ['CasbinObject', 'show'],
        ['CasbinAction', 'show'],
    ]
    menu = {}
    for r in rules:
        if verify_enforce(token, schemas.Casbin_rule(obj=r[0], act=r[1])):
            menu[r[0]] = True
        else:
            menu[r[0]] = False
    # print(menu)
    return menu

@router.post('/isAuthenticated')
async def isAuthenticated(rule: schemas.Casbin_rule, token: str = Depends(oauth2_scheme), ):
    """
    路由页面的权限验证接口
    :param rule:
    :param token:
    :return:
    """
    # print("路由权限验证")
    return verify_enforce(token, rule)

@router.post("/casbin_rule_test")
async def casbin_test(token: str = Depends(oauth2_scheme)):
    """
    一个关于权限接口的简单测试
    :param token:
    :return:
    """
    rule = schemas.Casbin_rule(obj='User', act='read')
    if verify_enforce(token, rule):
        return True
    else:
        return False
